package com.gt.wxpay.cashier.payment.interfaces.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gt.wxpay.cashier.application.RefundRemoteService;
import com.gt.wxpay.cashier.common.RedisLockUtils;
import com.gt.wxpay.cashier.common.RuleCommonUilt;
import com.gt.wxpay.cashier.domain.Result;
import com.gt.wxpay.cashier.domain.dto.QueryRefundDto;
import com.gt.wxpay.cashier.domain.model.CashierPayment;
import com.gt.wxpay.cashier.domain.model.PayTypeEnum;
import com.gt.wxpay.cashier.domain.model.RefundStatusEnum;
import com.gt.wxpay.cashier.domain.model.TransactionTypeEnum;
import com.gt.wxpay.cashier.payChannel.application.PayChannelService;
import com.gt.wxpay.cashier.payChannel.domain.model.PayChannel;
import com.gt.wxpay.cashier.payment.application.CheckCommonService;
import com.gt.wxpay.cashier.payment.application.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;

/**
 * 支付记录接口
 *
 * @author cztech
 */
@Slf4j
@RestController
@RequestMapping("/service/cashier/refund")
public class RefundServiceController implements RefundRemoteService {
    @Resource
    private PaymentService paymentService;


    @Autowired
    private TaskExecutor taskExecutor;

    @Autowired
    private CheckCommonService checkCommonService;

    @Autowired
    private PayChannelService payChannelService;


    /**
     * 当交易发生之后一段时间内，由于买家或者卖家的原因需要退款时，卖家可以通过退款接口将支付款退还给买家，
     * 微信支付将在收到退款请求并且验证成功之后，按照退款规则将支付款按原路退到买家帐号上。
     *
     * @param cashierPayment cashierPayment
     * @return Result
     */
    @RequestMapping("/create")
    @Override
    public Result<QueryRefundDto> create(CashierPayment cashierPayment) {
        cashierPayment.setStateId(1);
        Result<QueryRefundDto> refund;
        try {
            refund = Result.ok();
            QueryRefundDto refundNoDto = new QueryRefundDto();
            // 支付 校验必要参数
            String checkMsg = checkCommonService.payOrderRefundCheck(cashierPayment);
            if (checkMsg != null) {
                throw new RuntimeException(checkMsg);
            }
            CashierPayment query = new CashierPayment();
            query.setPaymentNo(cashierPayment.getPaymentNo());
            QueryWrapper<CashierPayment> queryWrapper = new QueryWrapper<>(query);
            // 获取原始订单信息
            CashierPayment fullcashierPayment = paymentService.getOne(queryWrapper);
            if (fullcashierPayment == null) {
                throw new RuntimeException(RuleCommonUilt.OPERATION_FAIL_BY_PAY_ORDER_NOT_FOUND);
            }
            cashierPayment.setCreator(fullcashierPayment.getPhoneNo());
            cashierPayment.setCreatorId(fullcashierPayment.getPayerId());
            long refundAmount = cashierPayment.getRefundAmount().longValue();
            long payAmount = fullcashierPayment.getAmount().longValue();
            if (refundAmount > payAmount) {
                throw new RuntimeException("退款金额不能大于支付金额");
            }
            // 分布式锁
            Boolean lock = RedisLockUtils.lock(RuleCommonUilt.PAY_REFUND_LOCK_PREFIX + cashierPayment.getPaymentNo(), "1", 60);
            if (!lock) {
                throw new RuntimeException("退款交易正在进行,请勿重复下单!!!");
            }
            String payChannelId = fullcashierPayment.getPayChannelId();
            // 获取渠道信息
            PayChannel payChannel = payChannelService.getById(Long.valueOf(payChannelId));
            // 判断支付渠道
            if (payChannel != null && PayTypeEnum.WECHAT.getCode() == payChannel.getPayChannel()) {
                // 直接进行入退款单的本地生成及时返回
                refundNoDto.setStatus(RefundStatusEnum.PROCESSING.getCode());
                String refundNoNextValue = RuleCommonUilt.getRefundNoNextValue();
                // 设置新的退款流水
                refundNoDto.setRefundNo(refundNoNextValue);
                cashierPayment.setPaymentNo(refundNoNextValue);
                refund.setResponse(refundNoDto);
                cashierPayment.setStateId(1);
                cashierPayment.setPayChannelId(payChannelId);
                cashierPayment.setRefundTime(new Date());
                cashierPayment.setChannelPayType(fullcashierPayment.getChannelPayType());
                // 设置交易类型退款
                cashierPayment.setTransactionType(TransactionTypeEnum.REFUND.code());
                // 生成新的退款单流水
                if (StringUtils.isBlank(cashierPayment.getPaymentNo())) {
                    log.error("退款单流水号不能为空");
                    throw new RuntimeException("退款单流水号不能为空");
                }
                cashierPayment.setStateId(1);
                // cashierPayment.setPaymentNo(RuleCommonUilt.getRefundNoNextValue());
                // 设置退款回调
                cashierPayment.setGoodsType(fullcashierPayment.getGoodsType());
                cashierPayment.setGoodsName(fullcashierPayment.getGoodsName());
                cashierPayment.setMerchantId(fullcashierPayment.getMerchantId());
                cashierPayment.setGoodsDesc(fullcashierPayment.getGoodsDesc());
                cashierPayment.setOrderNo(fullcashierPayment.getOrderNo());
                // 修改状态为退款中
                cashierPayment.setStatus(RefundStatusEnum.PROCESSING.getCode());
                // 原渠道侧流水号
                cashierPayment.setChannelFlowNo(fullcashierPayment.getChannelFlowNo());
                // 订单交易总资金
                cashierPayment.setAmount(fullcashierPayment.getAmount());
                cashierPayment.setCurrencyType(StringUtils.isEmpty(cashierPayment.getCurrencyType()) ? "CNY" : cashierPayment.getCurrencyType());
                cashierPayment.setAppId(fullcashierPayment.getAppId());
                // 生成退款单
                paymentService.save(cashierPayment);
                // 异步处理
                taskExecutor.execute(() -> paymentService.refund(cashierPayment));
            } else if (payChannel != null && PayTypeEnum.ALIPAY.getCode() == payChannel.getPayChannel()) {
                throw new RuntimeException("目前不支持支付宝支付");
            } else {
                throw new RuntimeException(RuleCommonUilt.NOT_SUPPER_TYPE);
            }
            RedisLockUtils.unlock(RuleCommonUilt.PAY_REFUND_LOCK_PREFIX + cashierPayment.getPaymentNo(), "1");
        } catch (Exception e) {
            log.error("退款失败", e);
            refund = Result.error(e.getMessage());
        }
        return refund;
    }

    /**
     * 提交退款申请后，通过调用该接口查询退款状态。退款有一定延时，建议查询退款状态在提交退款申请后1分钟发起，
     * 一般来说零钱支付的退款5分钟内到账，银行卡支付的退款1-3个工作日到账。
     *
     * @param refundNo refundNo (退款单号)
     * @return
     */
    @GetMapping("/query")
    @Override
    public Result<QueryRefundDto> query(@RequestParam String refundNo) {
        // 退款单校验
        CashierPayment cashierPayment = paymentService.queryByPamentNo(refundNo);
        if (cashierPayment == null) {
            return Result.error("退款单号不存在");
        }
        // 校验是否是退款订单
        Integer transactionType = cashierPayment.getTransactionType();
        if (!Objects.equals(transactionType, TransactionTypeEnum.REFUND.code())) {
            return Result.error("交易单号所在的订单不是退款单");
        }
        // 查询退款单--状态----微信侧业务处理
        QueryRefundDto queryRefundDto = null;
        try {
            queryRefundDto = paymentService.queryRefund(cashierPayment);
        } catch (Exception e) {
            log.error("退款查询失败", e);
            return Result.error(e.getMessage());
        }
        Result<QueryRefundDto> result = new Result<>();
        result.setResponse(queryRefundDto);
        result.setSuccess(true);
        return result;
    }


}
